feat(events): support LANGWATCH_PROJECT_ID via X-Project-Id header#619
feat(events): support LANGWATCH_PROJECT_ID via X-Project-Id header#6190xdeafcafe wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds support for multi-project LangWatch API keys by allowing both the Python and JavaScript event reporters to send a project scope identifier via X-Project-Id when configured, while standardizing authentication on Authorization: Bearer <api_key>.
Changes:
- Python: add
project_idsupport (env + constructor) and conditionally emitX-Project-Id; remove legacyX-Auth-Token. - JavaScript: add
projectIdplumbing fromrun()→EventBus→EventReporter, conditionally emittingX-Project-Id; switch toAuthorization: Bearer .... - Tests/docs: expand Python request-header tests to cover
X-Project-Idbehavior and bearer-only auth.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| python/tests/test_event_reporter.py | Updates header assertions for bearer-only auth and adds coverage for X-Project-Id emission and env fallback. |
| python/scenario/config/langwatch.py | Introduces project_id setting under the LANGWATCH_ env prefix. |
| python/scenario/_events/event_reporter.py | Adds project_id resolution and conditionally includes X-Project-Id; removes X-Auth-Token dual-emit. |
| javascript/src/runner/run.ts | Extends LangWatch runtime config to include projectId and passes it into the event system. |
| javascript/src/events/event-reporter.ts | Switches to bearer auth and conditionally emits X-Project-Id when configured. |
| javascript/src/events/event-bus.ts | Extends EventBus constructor config shape to accept/pass through projectId. |
| javascript/src/config/env.ts | Adds LANGWATCH_PROJECT_ID to the validated environment schema. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
LangWatch is moving to API keys that aren't bound to a single project; clients must send the project ID separately so the server can scope the request. Both event reporters now accept project_id/projectId (with LANGWATCH_PROJECT_ID env var) and emit X-Project-Id when set. Also switches authentication to Authorization: Bearer only and drops the legacy X-Auth-Token dual-emit on both reporters — the new server contract is bearer-only.
Adds parity with the Python suite — checks Authorization: Bearer is sent, X-Auth-Token is absent, X-Project-Id is sent only when projectId is configured, POST is skipped when apiKey is empty, and setUrl is returned from a successful response.
58badcd to
51a9a31
Compare
Resolves three JS conflicts where main (#545) also added cfg.langwatch config plumbing and moved LangwatchConfig into ../domain: - event-bus.ts / event-reporter.ts: keep main's projectId?: string signature and string | undefined field type; the PR's Authorization: Bearer headers replace the duplicate X-Auth-Token block auto-merge left in postEvent. - run.ts: drop the inline LangwatchConfig (now imported from ../domain) and merge the env / cfg.langwatch / options.langwatch resolution into a single three-tier fallback for endpoint, apiKey, and projectId. The previously-failing voice/test_feature_file_contract.py @Unit count also resolves automatically — main's tag bump arrives via this merge.
WalkthroughBoth the Python and JavaScript SDKs gain support for an optional ChangesLangWatch Project ID and Bearer Auth
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Automated low-risk assessment This PR was evaluated against the repository's Low-Risk Pull Requests procedure and does not qualify as low risk.
This PR requires a manual review before merging. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@python/tests/test_event_reporter.py`:
- Around line 70-72: The assertion checking that "X-Project-Id" is not in
request.headers can fail nondeterministically if the LANGWATCH_PROJECT_ID
environment variable is set, since EventReporter falls back to using that env
var for project_id. Before constructing the EventReporter instance in this test,
explicitly clear or unset the LANGWATCH_PROJECT_ID environment variable to
ensure the test runs in isolation from ambient environment state and produces
deterministic results.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3472c1bb-d73e-4ee2-832c-e38c40459417
📒 Files selected for processing (7)
javascript/src/config/env.tsjavascript/src/events/__tests__/event-reporter.test.tsjavascript/src/events/event-reporter.tsjavascript/src/runner/run.tspython/scenario/_events/event_reporter.pypython/scenario/config/langwatch.pypython/tests/test_event_reporter.py
| # Without project_id, no X-Project-Id header is sent — the API key is | ||
| # assumed to be project-bound. | ||
| assert "X-Project-Id" not in request.headers |
There was a problem hiding this comment.
Stabilize the “no X-Project-Id” assertion against ambient environment state.
Line 70-Line 72 can fail nondeterministically when LANGWATCH_PROJECT_ID is set in CI/dev shells, because EventReporter falls back to env project_id. Clear that env var in this test before constructing EventReporter.
Suggested patch
-async def test_post_event_sends_correct_request(caplog: LogCaptureFixture) -> None:
+async def test_post_event_sends_correct_request(
+ caplog: LogCaptureFixture,
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ monkeypatch.delenv("LANGWATCH_PROJECT_ID", raising=False)
endpoint = "https://app.langwatch.ai"
api_key = "test-api-key"
event = _make_event()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@python/tests/test_event_reporter.py` around lines 70 - 72, The assertion
checking that "X-Project-Id" is not in request.headers can fail
nondeterministically if the LANGWATCH_PROJECT_ID environment variable is set,
since EventReporter falls back to using that env var for project_id. Before
constructing the EventReporter instance in this test, explicitly clear or unset
the LANGWATCH_PROJECT_ID environment variable to ensure the test runs in
isolation from ambient environment state and produces deterministic results.
Why
LangWatch is moving to API keys that aren't bound to a single project; clients must send the project ID separately so the server can scope the request. Both event reporters currently send only an API key, so multi-project keys can't authorise.
What changed
LANGWATCH_PROJECT_IDenv var +project_id/projectIdconfig to the Python and JS event reporters, with the same resolution order asapi_key(explicit → env → default empty).Authorization: Bearer <api_key>only and drop the legacyX-Auth-Tokendual-emit on both reporters — the new server contract is bearer-only.X-Project-Id: <project_id>only when configured; project-bound API keys keep working with no extra config.Test plan
python/tests/test_event_reporter.py— added three tests forproject_id(explicit, env fallback, env→explicit precedence). Updated existing tests to assertAuthorization: Bearer …instead ofX-Auth-Token. All 11 tests pass.javascript/src/events/__tests__/event-reporter.test.ts— new file. Five tests:Authorization: Beareris sent andX-Auth-Tokenis absent;X-Project-Idis sent only whenprojectIdis configured; POST is skipped whenapiKeyis empty;setUrlis returned from a successful response.pnpm typecheckis clean for the touched files; pre-existing voice-module errors (missingffmpeg-static,elevenlabs,@amiceli/vitest-cucumber) are unchanged frommain.How I can prove I was successful
No playable artifact — see Test plan. Auth header behaviour is covered by both the Python and JS suites; the two reporter implementations mirror each other.